//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioModels
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Drawing;
    using System.IO;
    using System.Windows;
    using System.Windows.Media.Imaging;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using SR = Microsoft.Research.DataLayer;
    using System.Linq;
    using System.Text;
    using Microsoft.Research.eResearch.Common.Linq;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using System.Globalization;

    /// <summary>
    /// A view friendly model for the category.
    /// </summary>
    public class CategoryViewModel : BaseRegMgrModel
    {
        #region Private fields

        private Guid id;

        private string iconPath;

        private Image icon;

        private ObservableCollection<CategoryViewModel> childCategories = new ObservableCollection<CategoryViewModel>();

        private BaseRegMgrModel parent;

        private string categoryBreadcrumb;

        private BitmapImage registryImage;

        private BitmapImage savedImage;

        private BitmapImage previewImage;

        private string descriptiveText;

        private bool displayWorkflowCreate = false;

        private string centerPaneHeader;

        private CategoryType categoryType;

        private Guid displayId;

        private DateTime displayCreatedDate;

        private DateTime displayLastModifiedTime;

        private static Dictionary<Image, BitmapImage> imageToBitmapDictionary = new Dictionary<Image, BitmapImage>();

        private static BitmapImage defaultImage;

        private bool isNotVirtualCategory = true;

        private bool isEditable = true;

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor. An empty object will be created.
        /// </summary>
        public CategoryViewModel(CategoryType categoryType, BaseRegMgrModel parentModel)
        {
            this.CurrentCategoryType = categoryType;
            this.Parent = parentModel;
            if (this.Parent != null)
            {
                this.AllowChildCategories = (this.Parent as CategoryViewModel).AllowChildCategories;
            }

            this.IsSelected = false;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryViewModel"/> class. Initialize the model with information from the 
        /// passed category.
        /// </summary>
        /// <param name="category">The namespace item.</param>
        /// <param name="parent">The parent.</param>
        public CategoryViewModel(SR.Namespace category, CategoryViewModel parent, CategoryType categoryType, SR.SystemPolicy sysPolicy, bool allowChildCategories)
        {
            this.Name = category.Name;
            this.Label = string.IsNullOrEmpty(category.Label) ? category.Name : category.Label;
            this.Id = (category as SR.IObject).ID;
            this.Description = category.Description;
            this.Icon = category.Icon;
            this.SavedImage = CategoryViewModel.BitmapImageFromSDCtrl(category.Icon);
            this.CreatedBy = category.Created.User;
            this.CreatedDate = category.Created.When;
            this.LastModifiedBy = category.Updated.User;
            this.LastModifiedTime = category.Updated.When;
            this.Parent = parent;
            this.CurrentCategoryType = categoryType;
            this.AllowChildCategories = allowChildCategories;
            this.IsEditable = category.IsEditable;

            if (this.Parent == null)
            {
                if (this.Name.Equals(SR.Namespace.WorkflowRootName, StringComparison.OrdinalIgnoreCase))
                {
                    this.IsSelected = true;
                }

                this.CategoryBreadcrumb = this.Name;
                this.RootCategory = this;
            }
            else
            {
                CategoryViewModel parentCategory = this.Parent as CategoryViewModel;
                if (parentCategory != null)
                {
                    this.CategoryBreadcrumb = parentCategory.categoryBreadcrumb + " > " + this.Name;
                    this.RootCategory = parentCategory.RootCategory;
                }
            }

            if (categoryType == CategoryType.Activity)
            {
                IEnumerable<SR.Activity> activities = category.Activitys.Where(activity => !activity.IsWorkflow && !activity.IsHidden && !activity.IsDeleted);
                foreach (SR.Activity activity in activities)
                {
                    ActivityViewModel activityModel = new ActivityViewModel(activity, this);
                    if (activityModel.IsLatest)
                    {
                        this.Children.Add(activityModel);
                    }
                }
            }
            else if (categoryType == CategoryType.Workflow)
            {
                List<SR.Activity> workflows = category.Activitys.Where(
                        workflow => workflow.IsWorkflow
                        && !workflow.IsDeleted
                        && workflow.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser)).ToList();

                workflows.Sort(WorkflowNameComparer);
                foreach (SR.Activity workflow in workflows)
                {
                    bool addToTree = false;
                    bool isLatest = false;
                    if (!string.IsNullOrEmpty(workflow.VersionLabel))
                    {
                        addToTree = true;
                    }

                    // Check if latest version
                    workflow.NewerVersions.GetEnumerator();
                    if (workflow.NewerVersions.Count == 0)
                    {
                        addToTree = true;
                        isLatest = true;
                    }

                    if (addToTree)
                    {
                        WorkflowCatalogViewModel childWorkFlowModel = new WorkflowCatalogViewModel(workflow, this, isLatest, sysPolicy);
                        this.Children.Add(childWorkFlowModel);
                    }
                }
            }

            foreach (SR.Namespace childCategory in category.Children)
            {
                CategoryViewModel childModel = new CategoryViewModel(childCategory, this, this.CurrentCategoryType, sysPolicy, allowChildCategories);
                this.Children.Add(childModel);
                this.childCategories.Add(childModel);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryViewModel"/> class.
        /// </summary>
        /// <param name="categoryName">Name of the category.</param>
        /// <param name="childActivities">The child activities.</param>
        /// <param name="categoryType">Type of the category.</param>
        private CategoryViewModel(string categoryName, CategoryViewModel parent, IEnumerable<SR.Activity> childActivities, CategoryType categoryType, Guid categoryId, SR.SystemPolicy sysPolicy)
        {
            this.IsNotVirtualCategory = false;

            this.Name = this.Label = categoryName;
            this.Parent = parent;
            this.CurrentCategoryType = categoryType;
            this.Id = categoryId;
            this.AllowChildCategories = false;

            this.CategoryBreadcrumb = parent.categoryBreadcrumb + " > " + this.Name;
            this.RootCategory = parent.RootCategory;
            childActivities.Where(activity => (!activity.IsDeleted && (!string.IsNullOrEmpty(activity.VersionLabel) || activity.IsLatestVersion())))
                .ForEach(activity => this.Children.Add(new WorkflowCatalogViewModel(activity, this, true, sysPolicy)));
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryViewModel"/> class.
        /// Initialize from the passed model.
        /// </summary>
        /// <param name="model">The model.</param>
        private CategoryViewModel(CategoryViewModel model)
        {
            if (model != null)
            {
                this.Name = model.Name;
                this.Label = model.Label;
                this.Id = model.id;
                this.Description = model.Description;
                this.Icon = model.Icon;
                this.SavedImage = model.SavedImage;
                this.IconPath = model.IconPath;
                this.CreatedBy = model.CreatedBy;
                this.CreatedDate = model.CreatedDate;
                this.LastModifiedBy = model.LastModifiedBy;
                this.LastModifiedTime = model.LastModifiedTime;
                this.Parent = model.Parent;
                this.CategoryBreadcrumb = model.categoryBreadcrumb;
                this.RootCategory = model.RootCategory;
                this.IsNotVirtualCategory = model.IsNotVirtualCategory;
                this.CurrentCategoryType = model.CurrentCategoryType;
                this.IsSelected = model.IsSelected;
                this.AllowChildCategories = model.AllowChildCategories;
                this.IsEditable = model.IsEditable;

                foreach (BaseRegMgrModel childModel in model.Children)
                {
                    CategoryViewModel categoryViewModel = childModel as CategoryViewModel;
                    if (categoryViewModel != null)
                    {
                        CategoryViewModel clonedChildModel = new CategoryViewModel(categoryViewModel);
                        this.Children.Add(clonedChildModel);
                        this.childCategories.Add(clonedChildModel);
                    }
                    else
                    {
                        ActivityViewModel activityModel = childModel as ActivityViewModel;
                        if (activityModel != null)
                        {
                            ActivityViewModel clonedChildActivityModel = new ActivityViewModel(activityModel);
                            this.Children.Add(clonedChildActivityModel);
                        }
                    }
                }
            }
        }

        #endregion Constructors

        #region Public Properties

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public override Guid Id
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
                this.DisplayId = value;
                this.RaisePropertyChanged("Id");
            }
        }

        /// <summary>
        /// Gets or sets the display id.
        /// </summary>
        /// <value>The display id.</value>
        public Guid DisplayId
        {
            get
            {
                if (this.displayId.Equals(Guid.Empty))
                {
                    return (Guid)DependencyProperty.UnsetValue;
                }

                return this.displayId;
            }
            set
            {
                this.displayId = value;
                this.RaisePropertyChanged("DisplayId");
            }
        }

        /// <summary>
        /// Gets or sets the created date.
        /// </summary>
        /// <value>The created date.</value>
        public override DateTime CreatedDate
        {
            get
            {
                return base.CreatedDate;
            }
            set
            {
                base.CreatedDate = value;
                this.DisplayCreatedDate = value;
            }
        }

        /// <summary>
        /// Gets or sets the display created date.
        /// </summary>
        /// <value>The display created date.</value>
        public DateTime DisplayCreatedDate
        {
            get
            {
                if (DateTime.MinValue.Equals(this.displayCreatedDate))
                {
                    return (DateTime)DependencyProperty.UnsetValue;
                }

                return this.displayCreatedDate;
            }
            set
            {
                this.displayCreatedDate = value;
                this.RaisePropertyChanged("DisplayCreatedDate");
            }
        }

        /// <summary>
        /// Gets or sets the last modified time.
        /// </summary>
        /// <value>The last modified time.</value>
        public override DateTime LastModifiedTime
        {
            get
            {
                return base.LastModifiedTime;
            }
            set
            {
                base.LastModifiedTime = value;
                this.DisplayLastModifiedTime = value;
            }
        }

        /// <summary>
        /// Gets or sets the display last modified time.
        /// </summary>
        /// <value>The display last modified time.</value>
        public DateTime DisplayLastModifiedTime
        {
            get
            {
                if (DateTime.MinValue.Equals(this.displayLastModifiedTime))
                {
                    return (DateTime)DependencyProperty.UnsetValue;
                }

                return this.displayLastModifiedTime;
            }
            set
            {
                this.displayLastModifiedTime = value;
                this.RaisePropertyChanged("DisplayLastModifiedTime");
            }
        }

        /// <summary>
        /// Gets or sets the icon path.
        /// </summary>
        /// <value>The icon path.</value>
        public string IconPath
        {
            get
            {
                return string.IsNullOrEmpty(this.iconPath) ? "Trident Icon" : this.iconPath;
            }
            set
            {
                string newPath = value;
                string oldPath = this.IconPath;
                if (File.Exists(newPath))
                {
                    try
                    {
                        BitmapImage image = new BitmapImage();
                        image.BeginInit();
                        image.CacheOption = BitmapCacheOption.OnLoad;
                        image.UriSource = new Uri(newPath, UriKind.RelativeOrAbsolute);
                        image.DecodePixelWidth = Constants.BROWSEICONWIDTH;
                        image.EndInit();
                        this.PreviewImage = image;
                        this.iconPath = newPath;
                    }
                    catch (NotSupportedException ex)
                    {
                        TridentErrorHandler.HandleKnownExceptionsInUI(ex,
                            ManagementStudioResourceManager.GetString("InvalidImage"));
                        this.IconPath = oldPath;
                    }
                }

                this.RaisePropertyChanged("IconPath");
            }
        }

        /// <summary>
        /// Gets or sets the icon.
        /// </summary>
        /// <value>The icon.</value>
        public Image Icon
        {
            get { return icon; }
            set
            {
                icon = value;
                this.RegistryImage = CategoryViewModel.BitmapImageFromSDCtrl(this.Icon);
                this.RaisePropertyChanged("Icon");
            }
        }

        /// <summary>
        /// Gets or sets the parent.
        /// </summary>
        /// <value>The parent.</value>
        public override BaseRegMgrModel Parent
        {
            get
            {
                return parent;
            }
            set
            {
                parent = value;
                CategoryViewModel parentCategory = parent as CategoryViewModel;
                if (parentCategory != null)
                {
                    this.CategoryParentBreadcrumb = null == this.parent ? string.Empty : parentCategory.CategoryBreadcrumb;
                    this.RaisePropertyChanged("CategoryParentBreadCrumb");
                }

                this.RaisePropertyChanged("Parent");
            }
        }

        /// <summary>
        /// Gets the child categories.
        /// </summary>
        /// <value>The child categories.</value>
        public ObservableCollection<CategoryViewModel> ChildCategories
        {
            get
            {
                return this.childCategories;
            }
        }

        /// <summary>
        /// Gets or sets the root category.
        /// </summary>
        /// <value>The root category.</value>
        public CategoryViewModel RootCategory
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the category bread crumb.
        /// </summary>
        /// <value>The category bread crumb.</value>
        public string CategoryBreadcrumb
        {
            get
            {
                return this.categoryBreadcrumb;
            }
            set
            {
                this.categoryBreadcrumb = value;
                this.RaisePropertyChanged("CategoryBreadCrumb");
            }
        }

        /// <summary>
        /// Gets or sets the category parent bread crumb.
        /// </summary>
        /// <value>The category parent bread crumb.</value>
        public string CategoryParentBreadcrumb
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the preview image.
        /// </summary>
        /// <value>The preview image.</value>
        public BitmapImage PreviewImage
        {
            get
            {
                return this.previewImage != null ? this.previewImage : (BitmapImage)DependencyProperty.UnsetValue;
            }
            set
            {
                this.previewImage = value;
                if (this.previewImage != null && this.previewImage.CanFreeze)
                {
                    this.previewImage.Freeze();
                }

                this.RaisePropertyChanged("PreviewImage");
            }
        }

        /// <summary>
        /// Gets or sets the registry image.
        /// </summary>
        /// <value>The registry image.</value>
        public BitmapImage RegistryImage
        {
            get
            {
                return this.registryImage != null ? this.registryImage : (BitmapImage)DependencyProperty.UnsetValue;
            }
            set
            {
                this.registryImage = value;
                this.PreviewImage = null;
                if (this.registryImage != null && this.registryImage.CanFreeze)
                {
                    this.registryImage.Freeze();
                }

                this.RaisePropertyChanged("RegistryImage");
            }
        }

        /// <summary>
        /// Gets or sets the saved image.
        /// </summary>
        /// <value>The saved image.</value>
        public BitmapImage SavedImage
        {
            get
            {
                return this.savedImage != null ? this.savedImage : CategoryViewModel.DefaultImage;
            }
            set
            {
                this.savedImage = value;
                if (this.savedImage != null && this.savedImage.CanFreeze)
                {
                    this.savedImage.Freeze();
                }

                this.RaisePropertyChanged("SavedImage");
                this.RaisePropertyChanged("ItemIcon");
            }
        }

        /// <summary>
        /// Gets or sets the saved image.
        /// </summary>
        /// <value>The saved image.</value>
        public override BitmapImage ItemIcon
        {
            get
            {
                return this.SavedImage;
            }
            set
            {
                this.SavedImage = value;
            }
        }

        /// <summary>
        /// Holds the descriptive text of the model.
        /// </summary>
        public string DescriptiveText
        {
            get
            {
                return this.descriptiveText;
            }
            set
            {
                this.descriptiveText = value;
                this.RaisePropertyChanged("DescriptiveText");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to display workflow create and import options.
        /// </summary>        
        public bool DisplayWorkflowCreate
        {
            get
            {
                return this.displayWorkflowCreate;
            }
            set
            {
                this.displayWorkflowCreate = value;
                this.RaisePropertyChanged("DisplayWorkflowCreate");
            }
        }

        /// <summary>
        /// Gets or sets the center pane header.
        /// </summary>
        public string CenterPaneHeader
        {
            get
            {
                return this.centerPaneHeader;
            }
            set
            {
                this.centerPaneHeader = value;
                this.RaisePropertyChanged("CenterPaneHeader");
            }
        }

        /// <summary>
        /// Gets or sets the type of the current category.
        /// </summary>
        /// <value>The type of the current category.</value>
        public CategoryType CurrentCategoryType
        {
            get
            {
                return this.categoryType;
            }
            set
            {
                this.categoryType = value;
                if (this.CurrentCategoryType == CategoryType.Activity)
                {
                    this.DescriptiveText = ManagementStudioResourceManager.GetString("ActivityCategoryDescriptiveText");
                    StringBuilder centerPaneHeaderBuilder = new StringBuilder(ManagementStudioResourceManager.GetString("Activity"));
                    centerPaneHeaderBuilder.Append(" ");
                    centerPaneHeaderBuilder.Append(ManagementStudioResourceManager.GetString("Category"));
                    this.CenterPaneHeader = centerPaneHeaderBuilder.ToString();
                }
                else if (this.CurrentCategoryType == CategoryType.Workflow)
                {
                    this.DescriptiveText = this.IsNotVirtualCategory ? ManagementStudioResourceManager.GetString("WfCategoryDescriptiveText")
                        : ManagementStudioResourceManager.GetString("VirtualWfCategoryDescriptiveText");

                    StringBuilder centerPaneHeaderBuilder = new StringBuilder(ManagementStudioResourceManager.GetString("Workflow"));
                    centerPaneHeaderBuilder.Append(" ");
                    centerPaneHeaderBuilder.Append(ManagementStudioResourceManager.GetString("Category"));
                    this.CenterPaneHeader = centerPaneHeaderBuilder.ToString();
                    this.DisplayWorkflowCreate = true;
                }
                else
                {
                    this.DescriptiveText = ManagementStudioResourceManager.GetString("NonAssignedCategoryDescriptiveText");
                    this.CenterPaneHeader = ManagementStudioResourceManager.GetString("Category");
                }

                this.RaisePropertyChanged("CurrentCategoryType");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is virtual category.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is virtual category; otherwise, <c>false</c>.
        /// </value>
        public bool IsNotVirtualCategory
        {
            get
            {
                return this.isNotVirtualCategory;
            }
            set
            {
                this.isNotVirtualCategory = value;
                this.RaisePropertyChanged("IsNotVirtualCategory");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is editable.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is editable; otherwise, <c>false</c>.
        /// </value>
        public bool IsEditable
        {
            get
            {
                return this.isEditable;
            }
            set
            {
                this.isEditable = value;
                this.RaisePropertyChanged("IsEditable");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether allow child categories.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if allow child categories; otherwise, <c>false</c>.
        /// </value>
        public bool AllowChildCategories { get; set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// Creates the clone.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>
        /// The cloned model.
        /// </returns>
        public static CategoryViewModel CreateClone(CategoryViewModel model)
        {
            CategoryViewModel clonedModel = null;
            if (null != model)
            {
                clonedModel = new CategoryViewModel(model);
            }

            return clonedModel;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">
        /// The <paramref name="obj"/> parameter is null.
        /// </exception>
        public override bool Equals(object obj)
        {
            bool equal = false;
            CategoryViewModel equateParam = obj as CategoryViewModel;
            if (equateParam != null &&
                equateParam.Id.Equals(this.Id) &&
                CategoryViewModel.CheckEquality(equateParam.CategoryParentBreadcrumb, this.CategoryParentBreadcrumb) &&
                CategoryViewModel.CheckEquality(equateParam.Description, this.Description) &&
                CategoryViewModel.CheckEquality(equateParam.Icon, this.Icon) &&
                CategoryViewModel.CheckEquality(equateParam.IconPath, this.IconPath) &&
                CategoryViewModel.CheckEquality(equateParam.Name, this.Name) &&
                ((equateParam.Parent == null && this.Parent == null) ||
                (equateParam.Parent != null && this.Parent != null && equateParam.Parent.Id.Equals(this.Parent.Id))))
            {
                equal = true;
            }

            return equal;
        }

        /// <summary>
        /// Removes the child model.
        /// </summary>
        /// <param name="childModel">The child model.</param>
        /// <returns>Success or failure of the operation.</returns>
        public bool RemoveChildModel(CategoryViewModel childModel)
        {
            bool removeSuccess = true;
            if (this.Children.Contains(childModel))
            {
                removeSuccess = this.Children.Remove(childModel);
                if (this.ChildCategories.Contains(childModel))
                {
                    removeSuccess = this.ChildCategories.Remove(childModel);
                }
            }

            return removeSuccess;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return this.Name;
        }

        /// <summary>
        /// Updates the specified model.
        /// </summary>
        /// <param name="model">The model.</param>
        public override void Update(BaseRegMgrModel model)
        {
            CategoryViewModel categoryModel = model as CategoryViewModel;
            if (categoryModel != null)
            {
                this.Name = categoryModel.Name;
                this.Label = categoryModel.Label;
                this.Description = categoryModel.Description;
                this.CreatedDate = categoryModel.CreatedDate;
                this.CreatedBy = categoryModel.CreatedBy;
                this.LastModifiedTime = categoryModel.LastModifiedTime;
                this.LastModifiedBy = categoryModel.LastModifiedBy;
                this.ItemIcon = categoryModel.ItemIcon;
                this.Icon = categoryModel.Icon;
                this.IconPath = categoryModel.IconPath;
                this.CategoryParentBreadcrumb = categoryModel.CategoryParentBreadcrumb;
                this.CategoryBreadcrumb = categoryModel.CategoryBreadcrumb;
                this.CurrentCategoryType = categoryModel.CurrentCategoryType;
                this.RootCategory = categoryModel.RootCategory;

                this.IsEditable = categoryModel.IsEditable;

                foreach (BaseRegMgrModel child in categoryModel.Children)
                {
                    BaseRegMgrModel currentChild = child.GetModelById(child, this.Children);
                    if (currentChild != null)
                    {
                        currentChild.Update(child);
                    }
                }

                this.IsSelected = categoryModel.IsSelected;
            }
        }

        /// <summary>
        /// Updates the specified category.
        /// </summary>
        /// <param name="category">The category.</param>
        public void Update(SR.Namespace category)
        {
            this.Name = category.Name;
            this.Label = string.IsNullOrEmpty(category.Label) ? category.Name : category.Label;
            this.Id = (category as SR.IObject).ID;
            this.Description = category.Description;
            this.Icon = category.Icon;
            this.SavedImage = CategoryViewModel.BitmapImageFromSDCtrl(this.Icon);
            this.CreatedBy = category.Created.User;
            this.CreatedDate = category.Created.When;
            this.LastModifiedBy = category.Updated.User;
            this.LastModifiedTime = category.Updated.When;

            this.IsEditable = category.IsEditable;

            if (this.Parent == null)
            {
                this.CategoryBreadcrumb = this.Name;
                this.RootCategory = this;
            }
            else
            {
                CategoryViewModel parentCategory = this.Parent as CategoryViewModel;
                if (parentCategory != null)
                {
                    this.CategoryBreadcrumb = parentCategory.categoryBreadcrumb + " > " + this.Name;
                    this.RootCategory = parentCategory.RootCategory;
                }
            }
        }

        /// <summary>
        /// Generates the virtual category model.
        /// </summary>
        /// <param name="categoryName">Name of the category.</param>
        /// <param name="list">The list.</param>
        /// <param name="categoryType">Type of the category.</param>
        /// <returns></returns>
        public static CategoryViewModel GenerateVirtualCategoryModel(string categoryName, CategoryViewModel parent, IEnumerable<SR.Activity> list, CategoryType categoryType, Guid categoryId, SR.SystemPolicy sysPolicy)
        {
            return new CategoryViewModel(categoryName, parent, list, categoryType, categoryId, sysPolicy);
        }

        #endregion Public Methods

        #region Private Methods

        public static BitmapImage DefaultImage
        {
            get
            {
                if (null == CategoryViewModel.defaultImage)
                {
                    CategoryViewModel.CreateDefaultImage();
                }

                if (null != CategoryViewModel.defaultImage)
                {
                    return CategoryViewModel.defaultImage;
                }
                else
                {
                    return null;
                }
            }
        }

        public static BitmapImage BitmapImageFromSDCtrl(Image image)
        {
            BitmapImage bitmapImg = null;
            if (image != null)
            {
                if (!CategoryViewModel.imageToBitmapDictionary.TryGetValue(image, out bitmapImg))
                {
                    try
                    {
                        using (MemoryStream memStream = new MemoryStream())
                        {
                            image.Save(memStream, System.Drawing.Imaging.ImageFormat.Png);
                            bitmapImg = new BitmapImage();
                            bitmapImg.BeginInit();
                            bitmapImg.CacheOption = BitmapCacheOption.OnLoad;
                            bitmapImg.StreamSource = memStream;
                            bitmapImg.EndInit();
                        }

                        if (null == bitmapImg)
                        {
                            bitmapImg = CategoryViewModel.DefaultImage;
                        }
                        else
                        {
                            CategoryViewModel.imageToBitmapDictionary[image] = bitmapImg;
                        }
                    }
                    catch (Exception)
                    {
                        bitmapImg = CategoryViewModel.DefaultImage;
                    }
                }
            }
            else
            {
                bitmapImg = CategoryViewModel.DefaultImage;
            }

            return bitmapImg;
        }

        private static void CreateDefaultImage()
        {
            try
            {
                Uri uri = new Uri(@"pack://Application:,,,/Microsoft.Research.ScientificWorkflow.TridentUtilities;component/Images/ManagementStudio/categoriesHeaderPic.png", UriKind.Absolute);
                CategoryViewModel.defaultImage = new BitmapImage(uri);
                if (CategoryViewModel.defaultImage != null && CategoryViewModel.defaultImage.CanFreeze)
                {
                    CategoryViewModel.defaultImage.Freeze();
                }
            }
            catch (UriFormatException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
            catch (ArgumentException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
        }

        #endregion Private Methods

        /// <summary>
        /// Gets the model by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="coll">The collection.</param>
        /// <returns></returns>
        public override BaseRegMgrModel GetModelById(BaseRegMgrModel model, IEnumerable<BaseRegMgrModel> collection)
        {
            BaseRegMgrModel requiredModel = null;
            if (!model.Id.Equals(Guid.Empty))
            {
                foreach (BaseRegMgrModel currentModel in collection)
                {
                    if (currentModel.Id.Equals(model.Id))
                    {
                        requiredModel = currentModel;
                        break;
                    }
                    else
                    {
                        requiredModel = model.GetModelById(model, currentModel.Children);
                        if (requiredModel != null)
                        {
                            break;
                        }
                    }
                }
            }

            return requiredModel;
        }

        public int WorkflowNameComparer(SR.NamedObject<SR.Activity> first, SR.NamedObject<SR.Activity> second)
        {
            int result = 0;
            string firstStringToCompare = first.Name;
            string secondStringToCompare = second.Name;
            int compareValue = string.Compare(firstStringToCompare, secondStringToCompare, StringComparison.CurrentCultureIgnoreCase);
            if (compareValue != 0)
            {
                result = compareValue > 0 ? 1 : -1;
            }
            else
            {
                compareValue = DateTime.Compare(first.Updated.When, second.Updated.When);
                result = compareValue > 0 ? -1 : 1;
            }
            return result;
        }
    }

    /// <summary>
    /// The type of items the catgory holds.
    /// </summary>
    public enum CategoryType
    {
        None,
        Workflow,
        Activity
    }
}
